package com.yirui.serialcomm.service;

import com.fazecast.jSerialComm.SerialPort;
import com.yirui.serialcomm.core.Connector;
import com.yirui.serialcomm.core.MCChunkIterator;
import com.yirui.serialcomm.core.domain.SerialCommPacket;
import com.yirui.serialcomm.core.domain.StreamType;
import com.yirui.serialcomm.core.parse.MCPacketParser;
import com.yirui.serialcomm.core.parse.PacketParser;
import com.yirui.serialcomm.core.protocol.Context;
import com.yirui.serialcomm.core.protocol.SerialCommServer;
import com.yirui.serialcomm.core.protocol.TcpBridgeServer;
import com.yirui.serialcomm.core.protocol.UdpBridgeServer;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;

import java.io.PipedInputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Dujie
 * @create 2025/8/13
 * @since 1.0.0
 */
@Slf4j
public class SimpleConnection implements Connection{
    private AtomicBoolean runState = new AtomicBoolean();
    private SerialPort serialPort;
    private SerialCommServer serialCommServer;
    private UdpBridgeServer udpServer;
    private TcpBridgeServer tcpServer;
    private PacketParser packetParser = new MCPacketParser();
    private ExecutorService executorService;
    private Context context;
    public SimpleConnection(SerialPort port) {
        this.serialPort = port;
        executorService = Executors.newSingleThreadExecutor();
    }

    @Override
    public void startup(Context context) {
        if(runState.get()){
           return;
        }
        if(executorService.isShutdown()){
            executorService = Executors.newSingleThreadExecutor();
        }
        this.context = context;
        runState.set(true);
        log.info("***启动-串口【{}】到网络[{}:{}/tcp {}/udp]之间通信的代理服务",serialPort.getSystemPortName(), context.getTargetIp(),context.getTcpPort(), context.getUdpPort());

        //启动tcp服务
        tcpServer = new TcpBridgeServer(context.getTargetIp(), context.getTcpPort(), context.getPortAllocator());
        tcpServer.setPacketParser(this.packetParser);

        //启动upd 客户端
        udpServer = new UdpBridgeServer(context.getTargetIp(), context.getUdpPort(), context.getPortAllocator());
        udpServer.setPacketParser(this.packetParser);

        //启动串口服务
        serialCommServer = new SerialCommServer(serialPort);
        //串口专属管道连接器
        Connector serialCommConnector = new Connector();
        serialCommServer.setConnector(serialCommConnector);

        //创建网络连接对象
        Connector fullDuplexConnector = new Connector(); //tcp/udp公用管道连接器
        tcpServer.setConnector(fullDuplexConnector);
        udpServer.setConnector(fullDuplexConnector);

        try {
            //创建互为连接
            serialCommConnector.connectTo(fullDuplexConnector);
            fullDuplexConnector.connectTo(serialCommConnector);
            //启动
            tcpServer.start();
            udpServer.start();
            serialCommServer.start();

            startCommToNetWriteDataThread(fullDuplexConnector.getPipedInputStream(), serialCommServer.getMaxBufferSize());
        } catch (Exception e) {
            log.error("启动串口[{}]转网络服务异常:{}", serialPort.getSystemPortName(), e);
            close();
        }

    }

    private void startCommToNetWriteDataThread(PipedInputStream pipedInputStream, int maxBufferSize) {
        executorService.submit(()->{
            log.info("[启动] 从串口管道:{}获取数据转发到Net客户端:[{}/TCP {}/UDP].",serialPort.getSystemPortName(),context.getTcpPort(), context.getUdpPort());
            SerialCommPacket packet;
            MCChunkIterator<SerialCommPacket> iterator = new MCChunkIterator(pipedInputStream, packetParser);

            //收集断包数据
            while (runState.get()) {
                try {
                    if(iterator.hasNext()){
                        packet = iterator.next();

                        if(packet.getType() == StreamType.TCP){
                            tcpServer.send(Unpooled.copiedBuffer(packet.getData(), 0, packet.getData().length));
                        }else{
                            udpServer.send(Unpooled.copiedBuffer(packet.getData(), 0, packet.getData().length));
                        }
                    }


                } catch (Exception ex) {
                    log.error("从Net管道读取数据向Net客户端发生应答数据异常:{}", ex);
                }
            }

        });
    }

    @Override
    public void close() {

        runState.set(false);

        if(serialCommServer != null){
            serialCommServer.stop();
        }

        if(tcpServer != null){
            tcpServer.stop();
            tcpServer = null;
        }
        if(udpServer != null){
            udpServer.stop();
            udpServer = null;
        }
        if(executorService != null){
            executorService.shutdown();
        }
    }
}
